#ifndef OCL_INFO_H
#define OCL_INFO_H

namespace ocl
{
// http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clGetKernelInfo.html
// http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clGetKernelWorkGroupInfo.html
struct oclKernelInfo
{
    void Init(cl_kernel krl, cl_device_id dID)
    {
        OCL_CHKRET(oclGetKernelInfo(krl, CL_KERNEL_FUNCTION_NAME, OCL_NAME_MAX, oCL_KERNEL_FUNCTION_NAME, 0));
        OCL_CHKRET(oclGetKernelInfo(krl, CL_KERNEL_NUM_ARGS, sizeof(cl_uint), &oCL_KERNEL_NUM_ARGS, 0));

        OCL_CHKRET(oclGetKernelWorkGroupInfo(krl, dID, CL_KERNEL_WORK_GROUP_SIZE,         sizeof(size_t),   &oCL_KERNEL_WORK_GROUP_SIZE, 0));
        OCL_CHKRET(oclGetKernelWorkGroupInfo(krl, dID, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, sizeof(size_t)*3, oCL_KERNEL_COMPILE_WORK_GROUP_SIZE, 0));
        OCL_CHKRET(oclGetKernelWorkGroupInfo(krl, dID, CL_KERNEL_LOCAL_MEM_SIZE,          sizeof(cl_ulong), &oCL_KERNEL_LOCAL_MEM_SIZE, 0));
    };
    char             oCL_KERNEL_FUNCTION_NAME[OCL_NAME_MAX];
    cl_uint          oCL_KERNEL_NUM_ARGS;
    size_t           oCL_KERNEL_WORK_GROUP_SIZE;
    size_t           oCL_KERNEL_COMPILE_WORK_GROUP_SIZE[3];
    cl_ulong         oCL_KERNEL_LOCAL_MEM_SIZE;
};
// http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clGetDeviceInfo.html
struct oclDeviceInfo
{
    bool operator==(oclDeviceInfo& rhs)
    {
        return (   (oCL_DEVICE_TYPE    == rhs.oCL_DEVICE_TYPE)
                && (oCL_DEVICE_NAME    == rhs.oCL_DEVICE_NAME)
                && (oCL_DEVICE_VENDOR  == rhs.oCL_DEVICE_VENDOR)
                && (oCL_DRIVER_VERSION == rhs.oCL_DRIVER_VERSION)
               );
    };
    bool operator!=(oclDeviceInfo& rhs)
    {
        return !(*this == rhs);
    };
    void Init(cl_device_id dID)
    {
        id = dID;
        char buf[OCL_NAME_MAX] = {0};
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_TYPE,                               sizeof(cl_device_type), &oCL_DEVICE_TYPE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_ADDRESS_BITS,                       sizeof(cl_uint), &oCL_DEVICE_ADDRESS_BITS, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_AVAILABLE,                          sizeof(cl_bool), &oCL_DEVICE_AVAILABLE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_COMPILER_AVAILABLE,                 sizeof(cl_bool), &oCL_DEVICE_COMPILER_AVAILABLE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_ENDIAN_LITTLE,                      sizeof(cl_bool), &oCL_DEVICE_ENDIAN_LITTLE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_ERROR_CORRECTION_SUPPORT,           sizeof(cl_bool), &oCL_DEVICE_ERROR_CORRECTION_SUPPORT, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_EXTENSIONS,                         OCL_NAME_MAX, buf, 0)); oCL_DEVICE_EXTENSIONS = buf;
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,              sizeof(cl_ulong), &oCL_DEVICE_GLOBAL_MEM_CACHE_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE,              sizeof(cl_device_mem_cache_type), &oCL_DEVICE_GLOBAL_MEM_CACHE_TYPE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE,          sizeof(cl_uint), &oCL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_GLOBAL_MEM_SIZE,                    sizeof(cl_ulong), &oCL_DEVICE_GLOBAL_MEM_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_IMAGE_SUPPORT,                      sizeof(cl_bool), &oCL_DEVICE_IMAGE_SUPPORT, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_IMAGE2D_MAX_HEIGHT,                 sizeof(size_t), &oCL_DEVICE_IMAGE2D_MAX_HEIGHT, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_IMAGE2D_MAX_WIDTH,                  sizeof(size_t), &oCL_DEVICE_IMAGE2D_MAX_WIDTH, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_IMAGE3D_MAX_DEPTH,                  sizeof(size_t), &oCL_DEVICE_IMAGE3D_MAX_DEPTH, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_IMAGE3D_MAX_HEIGHT,                 sizeof(size_t), &oCL_DEVICE_IMAGE3D_MAX_HEIGHT, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_IMAGE3D_MAX_WIDTH,                  sizeof(size_t), &oCL_DEVICE_IMAGE3D_MAX_WIDTH, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_LOCAL_MEM_SIZE,                     sizeof(cl_ulong), &oCL_DEVICE_LOCAL_MEM_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_LOCAL_MEM_TYPE,                     sizeof(cl_device_local_mem_type), &oCL_DEVICE_LOCAL_MEM_TYPE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_CLOCK_FREQUENCY,                sizeof(cl_uint), &oCL_DEVICE_MAX_CLOCK_FREQUENCY, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_COMPUTE_UNITS,                  sizeof(cl_uint), &oCL_DEVICE_MAX_COMPUTE_UNITS, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_CONSTANT_ARGS,                  sizeof(cl_uint), &oCL_DEVICE_MAX_CONSTANT_ARGS, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE,           sizeof(cl_ulong), &oCL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_MEM_ALLOC_SIZE,                 sizeof(cl_ulong), &oCL_DEVICE_MAX_MEM_ALLOC_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_PARAMETER_SIZE,                 sizeof(size_t), &oCL_DEVICE_MAX_PARAMETER_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_READ_IMAGE_ARGS,                sizeof(cl_uint), &oCL_DEVICE_MAX_READ_IMAGE_ARGS, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_SAMPLERS,                       sizeof(cl_uint), &oCL_DEVICE_MAX_SAMPLERS, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_WORK_GROUP_SIZE,                sizeof(size_t), &oCL_DEVICE_MAX_WORK_GROUP_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS,           sizeof(cl_uint), &oCL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_WORK_ITEM_SIZES,                sizeof(size_t)*3, oCL_DEVICE_MAX_WORK_ITEM_SIZES, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MAX_WRITE_IMAGE_ARGS,               sizeof(cl_uint), &oCL_DEVICE_MAX_WRITE_IMAGE_ARGS, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MEM_BASE_ADDR_ALIGN,                sizeof(cl_uint), &oCL_DEVICE_MEM_BASE_ADDR_ALIGN, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE,           sizeof(cl_uint), &oCL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_NAME,                               OCL_NAME_MAX, buf, 0)); oCL_DEVICE_NAME = buf;
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PLATFORM,                           sizeof(cl_platform_id), &oCL_DEVICE_PLATFORM, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR,        sizeof(cl_uint), &oCL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT,       sizeof(cl_uint), &oCL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT,         sizeof(cl_uint), &oCL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG,        sizeof(cl_uint), &oCL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT,       sizeof(cl_uint), &oCL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE,      sizeof(cl_uint), &oCL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PROFILE,                            OCL_NAME_MAX, buf, 0)); oCL_DEVICE_PROFILE = buf;
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_PROFILING_TIMER_RESOLUTION,         sizeof(size_t), &oCL_DEVICE_PROFILING_TIMER_RESOLUTION, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_VENDOR,                             OCL_NAME_MAX, buf, 0)); oCL_DEVICE_VENDOR = buf;
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_VENDOR_ID,                          sizeof(cl_uint), &oCL_DEVICE_VENDOR_ID, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_VERSION,                            OCL_NAME_MAX, buf, 0)); oCL_DEVICE_VERSION = buf;
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DRIVER_VERSION,                            OCL_NAME_MAX, buf, 0)); oCL_DRIVER_VERSION = buf;
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_SINGLE_FP_CONFIG,                   sizeof(cl_device_fp_config), &oCL_DEVICE_SINGLE_FP_CONFIG, 0));
        //OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_DOUBLE_FP_CONFIG,                   sizeof(cl_device_fp_config), &oCL_DEVICE_DOUBLE_FP_CONFIG, 0));
        //OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_HALF_FP_CONFIG,                     sizeof(cl_device_fp_config), &oCL_DEVICE_HALF_FP_CONFIG, 0));
        OCL_CHKRET(oclGetDeviceInfo(dID, CL_DEVICE_QUEUE_PROPERTIES,                   sizeof(cl_command_queue_properties), &oCL_DEVICE_QUEUE_PROPERTIES, 0));
    };
    cl_device_id                id;
    cl_device_type              oCL_DEVICE_TYPE;
    cl_uint                     oCL_DEVICE_ADDRESS_BITS;
    cl_bool                     oCL_DEVICE_AVAILABLE;
    cl_bool                     oCL_DEVICE_COMPILER_AVAILABLE;
    cl_bool                     oCL_DEVICE_ENDIAN_LITTLE;
    cl_bool                     oCL_DEVICE_ERROR_CORRECTION_SUPPORT;
    std::string                 oCL_DEVICE_EXTENSIONS;
    cl_ulong                    oCL_DEVICE_GLOBAL_MEM_CACHE_SIZE;
    cl_device_mem_cache_type    oCL_DEVICE_GLOBAL_MEM_CACHE_TYPE;
    cl_uint                     oCL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE;
    cl_ulong                    oCL_DEVICE_GLOBAL_MEM_SIZE;
    cl_bool                     oCL_DEVICE_IMAGE_SUPPORT;
    size_t                      oCL_DEVICE_IMAGE2D_MAX_HEIGHT;
    size_t                      oCL_DEVICE_IMAGE2D_MAX_WIDTH;
    size_t                      oCL_DEVICE_IMAGE3D_MAX_DEPTH;
    size_t                      oCL_DEVICE_IMAGE3D_MAX_HEIGHT;
    size_t                      oCL_DEVICE_IMAGE3D_MAX_WIDTH;
    cl_ulong                    oCL_DEVICE_LOCAL_MEM_SIZE;
    cl_device_local_mem_type    oCL_DEVICE_LOCAL_MEM_TYPE;
    cl_uint                     oCL_DEVICE_MAX_CLOCK_FREQUENCY;
    cl_uint                     oCL_DEVICE_MAX_COMPUTE_UNITS;
    cl_uint                     oCL_DEVICE_MAX_CONSTANT_ARGS;
    cl_ulong                    oCL_DEVICE_MAX_CONSTANT_BUFFER_SIZE;
    cl_ulong                    oCL_DEVICE_MAX_MEM_ALLOC_SIZE;
    size_t                      oCL_DEVICE_MAX_PARAMETER_SIZE;
    cl_uint                     oCL_DEVICE_MAX_READ_IMAGE_ARGS;
    cl_uint                     oCL_DEVICE_MAX_SAMPLERS;
    size_t                      oCL_DEVICE_MAX_WORK_GROUP_SIZE;
    cl_uint                     oCL_DEVICE_MAX_WORK_ITEM_DIMENSIONS;
    size_t                      oCL_DEVICE_MAX_WORK_ITEM_SIZES[3];
    cl_uint                     oCL_DEVICE_MAX_WRITE_IMAGE_ARGS;
    cl_uint                     oCL_DEVICE_MEM_BASE_ADDR_ALIGN;
    cl_uint                     oCL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE;
    std::string                 oCL_DEVICE_NAME;
    cl_platform_id              oCL_DEVICE_PLATFORM;
    cl_uint                     oCL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR;
    cl_uint                     oCL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT;
    cl_uint                     oCL_DEVICE_PREFERRED_VECTOR_WIDTH_INT;
    cl_uint                     oCL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG;
    cl_uint                     oCL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT;
    cl_uint                     oCL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE;
    std::string                 oCL_DEVICE_PROFILE;
    size_t                      oCL_DEVICE_PROFILING_TIMER_RESOLUTION;
    std::string                 oCL_DEVICE_VENDOR;
    cl_uint                     oCL_DEVICE_VENDOR_ID;
    std::string                 oCL_DEVICE_VERSION;
    std::string                 oCL_DRIVER_VERSION;

    cl_device_fp_config         oCL_DEVICE_SINGLE_FP_CONFIG;
    //cl_device_fp_config         oCL_DEVICE_DOUBLE_FP_CONFIG;
    //cl_device_fp_config         oCL_DEVICE_HALF_FP_CONFIG;
    cl_command_queue_properties oCL_DEVICE_QUEUE_PROPERTIES;
};
// http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clGetPlatformInfo.html
struct oclPlatformInfo
{
    void Init(cl_platform_id pID)
    {
        id = pID;
        char buf[OCL_NAME_MAX] = {0};
        OCL_CHKRET(oclGetPlatformInfo(pID, CL_PLATFORM_PROFILE,     OCL_NAME_MAX, buf, 0));oCL_PLATFORM_PROFILE   =buf;
        OCL_CHKRET(oclGetPlatformInfo(pID, CL_PLATFORM_VERSION,     OCL_NAME_MAX, buf, 0));oCL_PLATFORM_VERSION   =buf;
        OCL_CHKRET(oclGetPlatformInfo(pID, CL_PLATFORM_NAME,        OCL_NAME_MAX, buf, 0));oCL_PLATFORM_NAME      =buf;
        OCL_CHKRET(oclGetPlatformInfo(pID, CL_PLATFORM_VENDOR,      OCL_NAME_MAX, buf, 0));oCL_PLATFORM_VENDOR    =buf;
        OCL_CHKRET(oclGetPlatformInfo(pID, CL_PLATFORM_EXTENSIONS,  OCL_NAME_MAX, buf, 0));oCL_PLATFORM_EXTENSIONS=buf;
    };
    cl_platform_id id;
    std::string oCL_PLATFORM_PROFILE;
    std::string oCL_PLATFORM_VERSION;
    std::string oCL_PLATFORM_NAME;
    std::string oCL_PLATFORM_VENDOR;
    std::string oCL_PLATFORM_EXTENSIONS;
};
}
#endif